package com.java.simple.study.juc.p2;

import com.java.simple.study.tool.Sleeper;
import lombok.extern.slf4j.Slf4j;

/**
 * @author zhoujunlin
 * @date 2022年04月05日 16:52
 * @desc
 */
@Slf4j(topic = "c.TestMakeTea")
public class TestMakeTea {

    public static void main(String[] args) {
        // 已经知道了 谁先完成  谁后完成
        //S1();
        // 不需要知道谁先水猴  但是不知道最终哪个线程执行最后的泡茶动作
        //S2.makeTea();
        // 确定一个线程用来执行泡茶动作  执行时机由其余线程完成后通知
        S3.makeTea();
    }

    private static void S1() {
        Thread t1 = new Thread(() -> {
            log.debug("洗水壶");
            Sleeper.sleep(1);

            log.debug("烧开水");
            Sleeper.sleep(15);

        }, "老王");

        Thread t2 = new Thread(() -> {
            log.debug("洗茶壶");
            Sleeper.sleep(1);

            log.debug("洗茶杯");
            Sleeper.sleep(2);

            log.debug("拿茶叶");
            Sleeper.sleep(1);

            try {
                t1.join();
                log.debug("开水已备好");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            log.debug("泡茶");
        }, "小王");
        t1.start();
        t2.start();
    }
}

@Slf4j(topic = "c.S2")
class S2 {
    static String kettle = "冷水";
    static String tea = null;
    static boolean maked = false;
    static final Object lock = new Object();

    public static void makeTea() {
        new Thread(() -> {
            log.debug("洗水壶");
            Sleeper.sleep(1);
            log.debug("烧开水");
            Sleeper.sleep(15);
            // 开水烧好时 获取锁
            synchronized (lock) {
                kettle = "开水";
                // 唤醒持有这把锁的其它线程
                lock.notifyAll();
                // 茶没有准备好时 等待
                while (tea == null) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (!maked) {
                    log.debug("拿（{}）抛（{}）", kettle, tea);
                    maked = true;
                }
            }
        }, "老王").start();

        new Thread(() -> {
            log.debug("洗茶壶");
            Sleeper.sleep(1);

            log.debug("洗茶杯");
            Sleeper.sleep(2);

            log.debug("拿茶叶");
            Sleeper.sleep(1);

            // 准备工作完成后  获取锁
            synchronized (lock) {
                tea = "大红袍";
                // 唤醒持有这把锁的其它线程
                lock.notifyAll();
                while ("冷水".equals(kettle)) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if (!maked) {
                    log.debug("拿（{}）抛（{}）", kettle, tea);
                    maked = true;
                }

            }

        }, "小王").start();

    }

}


@Slf4j(topic = "c.S3")
class S3 {
    static String kettle = "冷水";
    static String tea = null;
    static final Object lock = new Object();

    public static void makeTea() {
        new Thread(() -> {
            log.debug("洗水壶");
            Sleeper.sleep(1);
            log.debug("烧开水");
            Sleeper.sleep(15);
            // 开水烧好时 获取锁
            synchronized (lock) {
                kettle = "开水";
                // 唤醒持有这把锁的其它线程
                lock.notifyAll();
            }
        }, "老王").start();

        new Thread(() -> {
            log.debug("洗茶壶");
            Sleeper.sleep(1);

            log.debug("洗茶杯");
            Sleeper.sleep(2);

            log.debug("拿茶叶");
            Sleeper.sleep(1);

            // 准备工作完成后  获取锁
            synchronized (lock) {
                tea = "大红袍";
                // 唤醒持有这把锁的其它线程
                lock.notifyAll();
            }

        }, "小王").start();

        new Thread(() -> {
            synchronized (lock) {
                while ("冷水".equals(kettle) || tea == null) {
                    try {
                        lock.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                log.debug("拿（{}）抛（{}）", kettle, tea);
            }

        }, "王夫人").start();

    }

}